package com.phenix.mvp.base.multitype;

import android.content.Context;
import android.support.annotation.NonNull;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;

import com.phenix.mvp.util.TUtil;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import io.reactivex.Observable;


/**
 * @author  zhouphenix on 2017-1-8.
 */
public class MultiTypeAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{

    protected final List mList;
    protected TypePool mDelegate;
    private FlatTypeAdapter mFlatTypeAdapter;

    private Context mContext;
    private LayoutInflater mInflater;
    private int mCurrent;


    public MultiTypeAdapter(@NonNull Context mContext) {
        this(mContext, new ArrayList<>());
    }

    public MultiTypeAdapter(@NonNull Context mContext, @NonNull List<?> mList) {
        this(mContext, mList, new MultiTypePool());
    }

    public MultiTypeAdapter(@NonNull Context mContext, @NonNull List<?> mList, @NonNull TypePool mDelegate) {
        this(mContext, mList, mDelegate, new DefaultFlatTypeAdapter());
    }
    public MultiTypeAdapter(@NonNull Context mContext, @NonNull List<?> mList, int capacity) {
        this(mContext, mList, new MultiTypePool(capacity), new DefaultFlatTypeAdapter());
    }


    public MultiTypeAdapter(@NonNull Context mContext, @NonNull List<?> mList, @NonNull TypePool mDelegate, @NonNull FlatTypeAdapter mFlatTypeAdapter) {
        this.mContext = mContext;
        this.mList = mList;
        this.mDelegate = mDelegate;
        this.mFlatTypeAdapter = mFlatTypeAdapter;
        this.mInflater = LayoutInflater.from(mContext);

        applyGlobalMultiTypePool();

    }

    protected void applyGlobalMultiTypePool() {
        if (GlobalMultiTypePool.getViewHolders().size() > 0){//import全局注册的数据
            Observable.fromIterable(GlobalMultiTypePool.getViewHolders())
                    .subscribe(clazz -> {
                        register(clazz);
                        if (null != GlobalMultiTypePool.getTag(clazz))
                            setTag(clazz, GlobalMultiTypePool.getTag(clazz));
                    });
        }
    }


    public void setFlatTypeAdapter(FlatTypeAdapter mFlatTypeAdapter) {
        this.mFlatTypeAdapter = mFlatTypeAdapter;
    }

    public FlatTypeAdapter getFlatTypeAdapter() {
        return mFlatTypeAdapter;
    }

    public List getList() {
        return mList;
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        Class<? extends BaseViewHolder> clazz = mDelegate.getViewHolderByType(viewType);
        BaseViewHolder holder = TUtil.getInstance(clazz, new LinearLayout(mContext));
        final int layoutId = holder.getLayoutId((RecyclerView) parent, mCurrent);
        final View itemView = mInflater.inflate(layoutId, parent, false);
        if (null != mDelegate.getTag(clazz))
            Observable.fromIterable(mDelegate.getTag(clazz).entrySet()).subscribe(entry -> itemView.setTag(entry.getKey(), entry.getValue()));
        holder = TUtil.getInstance(clazz, itemView);
        holder.mMultiTypeAdapter = this;
        return holder;
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        ((BaseViewHolder)holder).onBindViewHolder(holder, mFlatTypeAdapter.onFlattenItem(getItem(position)));
    }


    @Override
    public int getItemCount() {
        return mList.size();
    }

    public <T>T getItem(int position){
        return (T) mList.get(position);
    }

    @Override
    public int getItemViewType(int position) {
        mCurrent = position;
        final Class clazz = mFlatTypeAdapter.onFlattenClass(getItem(position));
        final int index = mDelegate.indexOf(clazz);
        if (index == -1)throw new ViewHolderNotRegisterException(clazz);
        return index;
    }

    public void register(@NonNull Class<? extends BaseViewHolder>... clazzs) {
        mDelegate.register(mContext, clazzs);
    }

    public int indexOf(Class<?> clazz){
        return mDelegate.indexOf(clazz);
    }

    public void setTag(@NonNull Class<? extends BaseViewHolder> clazz, Map<Integer, Object> tags) {
        mDelegate.setTag(clazz, tags);
    }


    public void unregister(@NonNull Class<? extends BaseViewHolder> clazz) {
        mDelegate.unregister(clazz);
    }


    static class DefaultFlatTypeAdapter implements FlatTypeAdapter {
        @Override
        public Class<?> onFlattenClass(@NonNull Object o) {
            return o.getClass();
        }

        @Override
        public Object onFlattenItem(@NonNull Object o) {
            return o;
        }

    }
}
